package project.base.common.util
import org.springframework.data.redis.connection.DataType
import org.springframework.data.redis.core.Cursor
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.data.redis.core.ScanOptions
import org.springframework.stereotype.Component
import java.util.*
import java.util.concurrent.TimeUnit
import javax.annotation.Resource


/**
 * redis工具类
 * @author 三味
 * @since 2022/3/4 16:09
 */
@Component
open class RedisUtils {

    @Resource
    protected var redisTemplate: RedisTemplate<String, Any>? = null

    /** -------------------key相关操作---------------------  */
    /**
     * 删除key
     *
     * @param key
     */
    open fun delete(key: String?) {
        redisTemplate!!.delete(key)
    }

    /**
     * 批量删除key
     *
     * @param keys
     */
    open fun delete(keys: Collection<String?>?) {
        redisTemplate!!.delete(keys)
    }

    /**
     * 序列化key
     *
     * @param key
     * @return
     */
    open fun dump(key: String?): ByteArray? {
        return redisTemplate!!.dump(key)
    }

    /**
     * 是否存在key
     *
     * @param key
     * @return
     */
    open fun hasKey(key: String?): Boolean? {
        return redisTemplate!!.hasKey(key)
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param timeout
     * @param unit
     * @return
     */
    open fun expire(key: String?, timeout: Long, unit: TimeUnit?): Boolean? {
        return redisTemplate!!.expire(key, timeout, unit)
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param date
     * @return
     */
    open fun expireAt(key: String?, date: Date?): Boolean? {
        return redisTemplate!!.expireAt(key, date)
    }

    /**
     * 查找匹配的key
     *
     * @param pattern
     * @return
     */
    open fun keys(pattern: String?): Set<String?>? {
        return redisTemplate!!.keys(pattern)
    }

    /**
     * 将当前数据库的 key 移动到给定的数据库 db 当中
     *
     * @param key
     * @param dbIndex
     * @return
     */
    open fun move(key: String?, dbIndex: Int): Boolean? {
        return redisTemplate!!.move(key, dbIndex)
    }

    /**
     * 移除 key 的过期时间，key 将持久保持
     *
     * @param key
     * @return
     */
    open fun persist(key: String?): Boolean? {
        return redisTemplate!!.persist(key)
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @param unit
     * @return
     */
    open fun getExpire(key: String?, unit: TimeUnit?): Long? {
        return redisTemplate!!.getExpire(key, unit)
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @return
     */
    open fun getExpire(key: String?): Long? {
        return redisTemplate!!.getExpire(key)
    }

    /**
     * 从当前数据库中随机返回一个 key
     *
     * @return
     */
    open fun randomKey(): String? {
        return redisTemplate!!.randomKey()
    }

    /**
     * 修改 key 的名称
     *
     * @param oldKey
     * @param newKey
     */
    open fun rename(oldKey: String?, newKey: String?) {
        redisTemplate!!.rename(oldKey, newKey)
    }

    /**
     * 仅当 newkey 不存在时，将 oldKey 改名为 newkey
     *
     * @param oldKey
     * @param newKey
     * @return
     */
    open fun renameIfAbsent(oldKey: String?, newKey: String?): Boolean? {
        return redisTemplate!!.renameIfAbsent(oldKey, newKey)
    }

    /**
     * 返回 key 所储存的值的类型
     *
     * @param key
     * @return
     */
    open fun type(key: String?): DataType? {
        return redisTemplate!!.type(key)
    }

    /** -------------------string相关操作---------------------  */
    /**
     * 设置指定 key 的值
     * @param key
     * @param value
     */
    open operator fun set(key: String?, value: String?, offset: Long) {
        redisTemplate!!.opsForValue().set(key, value, offset)
    }

    /**
     * 获取指定 key 的值
     * @param key
     * @return
     */
    open operator fun get(key: String?): String? {
        return redisTemplate!!.opsForValue().get(key) as String?
    }

    /**
     * 返回 key 中字符串值的子字符
     * @param key
     * @param start
     * @param end
     * @return
     */
    open fun getRange(key: String?, start: Long, end: Long): String? {
        return redisTemplate!!.opsForValue().get(key, start, end)
    }

    /**
     * 将给定 key 的值设为 value ，并返回 key 的旧值(old value)
     *
     * @param key
     * @param value
     * @return
     */
    open fun getAndSet(key: String?, value: String?): String? {
        return redisTemplate!!.opsForValue().getAndSet(key, value) as String?
    }

    /**
     * 对 key 所储存的字符串值，获取指定偏移量上的位(bit)
     *
     * @param key
     * @param offset
     * @return
     */
    open fun getBit(key: String?, offset: Long): Boolean? {
        return redisTemplate!!.opsForValue().getBit(key, offset)
    }

    /**
     * 批量获取
     *
     * @param keys
     * @return
     */
    open fun multiGet(keys: Collection<String?>?): List<String?>? {
        return redisTemplate!!.opsForValue().multiGet(keys) as List<String?>?
    }

    /**
     * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
     *
     * @param key
     * @param postion
     * 位置
     * @param value
     * 值,true为1, false为0
     * @return
     */
    open fun setBit(key: String?, offset: Long, value: Boolean): Boolean {
        return redisTemplate!!.opsForValue().setBit(key, offset, value)
    }

    /**
     * 将值 value 关联到 key ，并将 key 的过期时间设为 timeout
     *
     * @param key
     * @param value
     * @param timeout
     * 过期时间
     * @param unit
     * 时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
     * 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
     */
    open fun setEx(key: String?, value: String?, timeout: Long, unit: TimeUnit?) {
        redisTemplate!!.opsForValue().set(key, value, timeout, unit)
    }

    /**
     * 只有在 key 不存在时设置 key 的值
     *
     * @param key
     * @param value
     * @return 之前已经存在返回false,不存在返回true
     */
    open fun setIfAbsent(key: String?, value: String?): Boolean {
        return redisTemplate!!.opsForValue().setIfAbsent(key, value)
    }

    /**
     * 用 value 参数覆写给定 key 所储存的字符串值，从偏移量 offset 开始
     *
     * @param key
     * @param value
     * @param offset
     * 从指定位置开始覆写
     */
    open fun setRange(key: String?, value: String?, offset: Long) {
        redisTemplate!!.opsForValue().set(key, value, offset)
    }

    /**
     * 获取字符串的长度
     *
     * @param key
     * @return
     */
    open fun size(key: String?): Long? {
        return redisTemplate!!.opsForValue().size(key)
    }

    /**
     * 批量添加
     *
     * @param maps
     */
    open fun multiSet(maps: Map<String?, String?>?) {
        redisTemplate!!.opsForValue().multiSet(maps)
    }

    /**
     * 同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在
     *
     * @param maps
     * @return 之前已经存在返回false,不存在返回true
     */
    open fun multiSetIfAbsent(maps: Map<String?, String?>?): Boolean {
        return redisTemplate!!.opsForValue().multiSetIfAbsent(maps)
    }

    /**
     * 增加(自增长), 负数则为自减
     *
     * @param key
     * @param value
     * @return
     */
    open fun incrBy(key: String?, increment: Long): Long? {
        return redisTemplate!!.opsForValue().increment(key, increment)
    }

    /**
     *
     * @param key
     * @param value
     * @return
     */
    open fun incrByFloat(key: String?, increment: Double): Double? {
        return redisTemplate!!.opsForValue().increment(key, increment)
    }

    /**
     * 追加到末尾
     *
     * @param key
     * @param value
     * @return
     */
    open fun append(key: String?, value: String?): Int? {
        return redisTemplate!!.opsForValue().append(key, value)
    }

    /** -------------------hash相关操作-------------------------  */
    /**
     * 获取存储在哈希表中指定字段的值
     *
     * @param key
     * @param field
     * @return
     */
    open fun hGet(key: String?, field: String?): Any? {
        return redisTemplate!!.opsForHash<Any, Any>().get(key, field)
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @return
     */
    open fun hGetAll(key: String?): Map<Any?, Any?>? {
        return redisTemplate!!.opsForHash<Any, Any>().entries(key)
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @param fields
     * @return
     */
    open fun hMultiGet(key: String?, fields: Collection<Any?>?): List<Any?>? {
        return redisTemplate!!.opsForHash<Any, Any>().multiGet(key, fields)
    }

    open fun hPut(key: String?, hashKey: String?, value: String?) {
        redisTemplate!!.opsForHash<Any, Any>().put(key, hashKey, value)
    }

    open fun hPutAll(key: String?, maps: Map<String?, String?>?) {
        redisTemplate!!.opsForHash<Any, Any>().putAll(key, maps)
    }

    /**
     * 仅当hashKey不存在时才设置
     *
     * @param key
     * @param hashKey
     * @param value
     * @return
     */
    open fun hPutIfAbsent(key: String?, hashKey: String?, value: String?): Boolean? {
        return redisTemplate!!.opsForHash<Any, Any>().putIfAbsent(key, hashKey, value)
    }

    /**
     * 删除一个或多个哈希表字段
     *
     * @param key
     * @param fields
     * @return
     */
    open fun hDelete(key: String?, vararg fields: Any?): Long? {
        return redisTemplate!!.opsForHash<Any, Any>().delete(key, *fields)
    }

    /**
     * 查看哈希表 key 中，指定的字段是否存在
     *
     * @param key
     * @param field
     * @return
     */
    open fun hExists(key: String?, field: String?): Boolean {
        return redisTemplate!!.opsForHash<Any, Any>().hasKey(key, field)
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param increment
     * @return
     */
    open fun hIncrBy(key: String?, field: Any?, increment: Long): Long? {
        return redisTemplate!!.opsForHash<Any, Any>().increment(key, field, increment)
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param delta
     * @return
     */
    open fun hIncrByFloat(key: String?, field: Any?, delta: Double): Double? {
        return redisTemplate!!.opsForHash<Any, Any>().increment(key, field, delta)
    }

    /**
     * 获取所有哈希表中的字段
     *
     * @param key
     * @return
     */
    open fun hKeys(key: String?): Set<Any?>? {
        return redisTemplate!!.opsForHash<Any, Any>().keys(key)
    }

    /**
     * 获取哈希表中字段的数量
     *
     * @param key
     * @return
     */
    open fun hSize(key: String?): Long? {
        return redisTemplate!!.opsForHash<Any, Any>().size(key)
    }

    /**
     * 获取哈希表中所有值
     *
     * @param key
     * @return
     */
    open fun hValues(key: String?): List<Any?>? {
        return redisTemplate!!.opsForHash<Any, Any>().values(key)
    }

    /**
     * 迭代哈希表中的键值对
     *
     * @param key
     * @param options
     * @return
     */
    open fun hScan(key: String?, options: ScanOptions?): Cursor<Map.Entry<Any?, Any?>?>? {
        return redisTemplate!!.opsForHash<Any, Any>().scan(key, options)
    }

    /** ------------------------list相关操作----------------------------  */
    /**
     * 通过索引获取列表中的元素
     *
     * @param key
     * @param index
     * @return
     */
    open fun lIndex(key: String?, index: Long): String? {
        return redisTemplate!!.opsForList().index(key, index) as String?
    }

    /**
     * 获取列表指定范围内的元素
     *
     * @param key
     * @param start
     * 开始位置, 0是开始位置
     * @param end
     * 结束位置, -1返回所有
     * @return
     */
    open fun lRange(key: String?, start: Long, end: Long): List<String?>? {
        return redisTemplate!!.opsForList().range(key, start, end) as List<String?>?
    }

    /**
     * 存储在list头部
     *
     * @param key
     * @param value
     * @return
     */
    open fun lLeftPush(key: String?, value: String?): Long? {
        return redisTemplate!!.opsForList().leftPush(key, value)
    }

    /**
     *
     * @param key
     * @param value
     * @return
     */
    open fun lLeftPushAll(key: String?, vararg value: String?): Long? {
        return redisTemplate!!.opsForList().leftPushAll(key, *value)
    }


    /**
     * 当list存在的时候才加入
     *
     * @param key
     * @param value
     * @return
     */
    open fun lLeftPushIfPresent(key: String?, value: String?): Long? {
        return redisTemplate!!.opsForList().leftPushIfPresent(key, value)
    }

    /**
     * 如果pivot存在,再pivot前面添加
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    open fun lLeftPush(key: String?, pivot: String?, value: String?): Long? {
        return redisTemplate!!.opsForList().leftPush(key, pivot, value)
    }

    /**
     *
     * @param key
     * @param value
     * @return
     */
    open fun lRightPush(key: String?, value: String?): Long? {
        return redisTemplate!!.opsForList().rightPush(key, value)
    }

    /**
     *
     * @param key
     * @param value
     * @return
     */
    open fun lRightPushAll(key: String?, vararg value: String?): Long? {
        return redisTemplate!!.opsForList().rightPushAll(key, *value)
    }

}
